Snowflake マイクロパーティションとデータクラスタリングの解説 | Snowflake Advent Calendar 2019 #SnowflakeDB
Snowflakeの速さの秘訣はプルーニングであり、効果的にプルーニングするにはデータクラスタリングが必要です。クラスタ化したデータを効率的に扱えるデータファイルがマイクロパーティションとなります。今日はSnoflakeの基礎の基礎、マイクロパーティションとデータクラスタリングの解説します。
マイクロパーティション
マイクロパーティションとは
マイクロパーティションは、Snowflakeのテーブルのデータを格納するファイルです。例えば、Stageに配置したデータファイルはCOPYコマンドでロードすると自動的に取り込み順序に基づいて連続したマイクロパーティションに保存されます。マイクロパーティションは、イミュータブル(変更不可能)な特性を持つので、更新する度に新しいファイルが作成します。
- テーブルデータを保持する連続したストレージユニット
- 50〜500 MBの非圧縮データを圧縮して、一般的に16MB(圧縮)になる
- テーブル毎に複数のマイクロパーティションが作成される
- IMMUTABLE
- サービス層は、すべてのマイクロパーティションに関するメタデータを保存する
- MIN / MAX(各列の値の範囲)
- distinct valuesの数
特長
- DML操作(DELETE、UPDATE、MERGEなど)は、潜在的なマイクロパーティションメタデータを利用して、テーブルのメンテナンスを簡素化します
- テーブルからすべての行を削除するなどの一部の操作は、メタデータのみの操作です
- MIN、MAX、COUNTなどの集計操作はメタデータのみの操作です
データクラスタリング
ナチュラルデータクラスタリング
データクラスタリングとは、データを分類することを表します。ナチュラルデータクラスタリングは、Stageからロードした順に基づいてデータを分類します。例えば、毎日データをロードすると自然と日付順にデータが配置されますが、更に日付と1つ以上のカラムとは相関しているという特性を活かしてデータを分類します。
- データがテーブルにロードされると、データをロードされた順にマイクロパーティションが作成される
- データロードした日付と1つ以上のカラムとは相関しているという特性を活かす
- シーケンシャルフィールドを持つテーブル
- 日付フィールドを持つテーブル
どうやって決定するのか?
1回のデータロードでソースデータを読み取り、マイクロパーティションに書き込みます。次にソースデータの構成が、マイクロパーティションで表現される値の範囲を決定します。
例えば、
- ソースデータには特定の日の行が含まれ、その日のデータは連続したマイクロパーティションになる
- ソースデータには1か月または1年の行が含まれ、マイクロパーティションにはその月または年内の日付の最大値/最小値があります
クラスタリングキーによるクラスタ化テーブル
前述の通り、全てのテーブルはデータの取り込みに基づいたナチュラルデータクラスタリングを利用できますが、任意のキーでクラスタリングすることも可能です。
- 特定のカラムまたは式で「キー」をクラスタリングし、その後
- 必要に応じてバックグラウンドで再クラスター化
- 最大1〜3個のキーを使用することが推奨、キーが多いことが良いことではありません
- 低いカーディナリティから高いカーディナリティの順に設定
クラスタリングキーは、クラスタリングに使用するカラムまたは式を指定します。クラスタリング後、同じクラスタリングキーのデータは同じマイクロパーティションにロードされます。クラスタリングテーブルのメンテナンスはSnowflake自動クラスタリングサービスによって処理され、1秒ごとに請求されます。
常にクラスタ化テーブルが良いとは限らない
クラスタリングキーはすべてのテーブルにとって良い選択とは限りません。
- 自動クラスタリングはクレジットを消費します
- 再クラスタリングはストレージコストも増加させます
- テーブルをロードした後、クラスターキーを追加するのに費用がかからない
- 自動クラスタリングを無効にすることができます
- クラスタリングキー選定のポイント:
- 数テラバイト規模のテーブルでは、クラスタリングのメリットが最も大きくなります。
- 特に、DMLがこれらの表で定期的に実行される場合は有効です
- 頻繁に変更されないテーブルは、再クラスター化のコストが低くなります
- 時間経過とともにクエリのパフォーマンスが著しく低下するテーブル
クラスタキーの設定例
-- テーブル作成時にクラスタキーとなるカラム名を指定する例 CREATE TABLE t1 (c1 date, c2 string, c3 number) CLUSTER BY (c1, c2); -- テーブル作成時にクラスタキーとなる式を指定する例 CREATE TABLE t2 (c1 timestamp, c2 string, c3 number) CLUSTER BY (TO_DATE(c1), SUBSTRING(c2, 0, 10)); -- 既存のテーブルにクラスタキーとなるカラム名を指定する例 ALTER TABLE t1 CLUSTER BY (c1, c3); -- 既存のテーブルにクラスタキーとなる式を指定する例 ALTER TABLE t2 CLUSTER BY (SUBSTRING(c2, 5, 10), TO_DATE(c1));
パーティションプルーニング
クエリでプルーニングする
これまでデータをなぜデータをクラスタ化して保存したかというと、クエリでプルーニングをしたかったからです。クラスタ化の目的は不必要なデータの読み取りを削減(プルーニング)するためです。(プルーニングとは英語で「剪定(せんてい)」の意で、木の余計な枝を切るように、余計なデータを切ってしまうことの比喩的表現です。)
- データがテーブルに挿入/ロードされると、プロセス中に作成された各マイクロパーティションのクラスタリングメタデータが収集および記録されます
- Snowflakeはこのクラスタリング情報を活用して、クエリ中のマイクロパーティションの不要なスキャンを回避します
- これらのカラムを参照するクエリのパフォーマンスを大幅に向上します
プルーニングの例
例えば、3,000億件のレコードが722,313個のパーティションファイルに分割されていた場合、クエリは「1840」を含むパーティションファイルのみを読み取りで済むため、余計なファイルの読み取りや処理が不要になり高速になります。
最後に
Snowflakeは効率的にプルーニングするためにデータをクラスタリングしてマイクロパーティションに格納しているので、不要なファイルの読み取りを効果的に削減できます。Snowflakeはクラスタキーを設定しなくてもナチュラルオーダーでデータをプルーニングできますが、分類したいキーが明らかな場合はクラスタキーを指定した方がベターです。
一般的なデータウェアハウスやデータレイクにクラスタキー相当の設定をすると同様にプルーニングできるようになりますが、事前のETLやデータロード時のソートなどのコストが発生します。一方、Snowflakeはロード時にナチュラルーオーダーでロードするので非常に高速です。データのクラスタリングやソートはフルマネージドサービスレイヤがバックグラウンドで非同期実行して、常に最適なパフォーマンスが得られる状態を維持します。大規模なテーブルの場合、ほとんどのデータがクラスタ化されているため、クエリが常に高速になります。しかし、自動クラスタリングはクレジットの消費やストレージコストも生じるのでユースケースに応じて使い分けるということも忘れない方が良いでしょう。